package com.duan.learn.collection;

import com.google.gson.Gson;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * HashMap测试类
 * 1. 验证带参
 */
public class HashMapTest {

    /**
     * 利用反射获取扩容的阈值
     * @param obj
     * @return
     * @throws Exception
     */
    public int getField(Object obj, String fieldName) throws Exception {
        Class<?> classObj = Class.forName(obj.getClass().getName());
        Object newObj = classObj.newInstance();
        Field field = newObj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return (int)field.get(obj);
    }

    /**
     * 利用反射调用内部方法
     * @param obj 对象
     * @param methodName 方法名
     * @param isPublic if true, 调用public方法，if false，调用非public方法
     */
    public Object invoke(Object obj, String methodName,boolean isStatic, boolean isPublic, Object... args) throws Exception {
        Class<?> classObj = Class.forName(obj.getClass().getName());
        Method method;
        if (isStatic) { // 静态方法
            if (isPublic) {
                method = classObj.getMethod(methodName, args.getClass());
            } else {
                // Object.class不能用args.getClass()替换，否则会报错
                method = HashMap.class.getDeclaredMethod(methodName, Object.class);
                method.setAccessible(true);
            }
            return method.invoke(null, args);
        } else { // 非静态方法
            if (isPublic) { // 非static的public方法
                method = classObj.getMethod(methodName);
            } else { // 非static、非public方法
                method = classObj.getDeclaredMethod(methodName);
                method.setAccessible(true);
            }
            return method.invoke(obj, args);
        }
    }

    /**
     * 利用反射获取map的表格元素
     *
     * 注：因为这里暂时没有找到合适的方法可以返回HashMap$Node类型，所以自定义了一个和HashMap$Node属性相同类Node，
     * 利用反射获取到HashMap$Node的对象后，再利用gson转换成自定义Node类型
     * @param obj
     * @return
     * @throws Exception
     */
    public Object[] getTable(HashMap obj) throws Exception {
        Class<?> classObj = Class.forName(obj.getClass().getName());
        Object newObj = classObj.newInstance();
        Field field = newObj.getClass().getDeclaredField("table");
        field.setAccessible(true);
        Object object = field.get(obj);
        if (object.getClass().isArray()) {
            return (Object []) object;
        }
        return null;
    }

    /**
     * 获取静态内部类
     */
    public Class getInnerClass(Class classz, String innerClassName) {
        Class innerCls[] = classz.getDeclaredClasses();
        for(Class innerClass : innerCls) {
            if (innerClass.getClass().getName().equals(innerClassName)) {
                return innerClass;
            }
        }
        return Object.class;

    }

}
